﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;

namespace Common.Reflection
{
    /// <summary>
    /// 表示一些常用的反射操作
    /// </summary>
    public static class ReflectionActions
    {
        /// <summary>
        /// 获取指定方法（接口的方法）的实现
        /// </summary>
        /// <param name="targetType">接口的实现</param>
        /// <param name="interfaceMethodInfo">定义在接口上的方法</param>
        /// <returns></returns>
        public static MethodInfo GetImplementOfInterfaceMethod(this Type targetType, MethodInfo interfaceMethodInfo)
        {
            var interfaceType = interfaceMethodInfo.DeclaringType;
            Trace.Assert(interfaceType != null);
            Trace.Assert(interfaceType.IsInterface);
            var map = targetType.GetInterfaceMap(interfaceType);
            var index = Array.IndexOf(map.InterfaceMethods, interfaceMethodInfo);
            return index < 0 ? null : map.TargetMethods[index];
        }

        /// <summary>
        /// 比对两个泛型参数类型是否一致
        /// </summary>
        /// <typeparam name="T1"></typeparam>
        /// <typeparam name="T2"></typeparam>
        /// <returns></returns>
        public static bool Is<T1, T2>()
        {
            return typeof(T1) == typeof(T2);
        }

        /// <summary>
        /// 比对泛型参数的类型和指定的类型实例是否一致
        /// </summary>
        /// <typeparam name="T1"></typeparam>
        /// <param name="type2"></param>
        /// <returns></returns>
        public static bool Is<T1>(this Type type2)
        {
            return typeof(T1) == type2;
        }

        /// <summary>
        /// 判断该类型是否兼容指定的类型
        /// </summary>
        /// <typeparam name="T1"></typeparam>
        /// <param name="type2"></param>
        /// <returns></returns>
        public static bool HasAncestry<T1>(this Type type2)
        {
            return typeof(T1).IsAssignableFrom(type2);
        }

        public static bool IsAttributeDefined<TAttr>(this Type type)
        {
            return type.GetCustomAttributes(typeof(TAttr)).Any();
        }

        /// <summary>
        /// 读取在对象类型上定义的Description属性
        /// </summary>
        /// <param name="target"></param>
        /// <returns></returns>
        public static string ReadDescription(this object target)
        {
            return Is<Type>(target.GetType()) || target is Type
                ? ReadDescrition(target as Type)
                : ReadDescrition(target.GetType());
        }

        /// <summary>
        /// 读取在对象类型上定义的Description特性
        /// </summary>
        /// <param name="type"></param>
        /// <returns></returns>
        private static string ReadDescrition(Type type)
        {
            var attr = type.GetCustomAttributes()
                .OfType<DescriptionAttribute>().FirstOrDefault();
            return attr != null ? attr.Description : null;
        }

        /// <summary>
        /// 读取在类型成员上定义的Description特性
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="target"></param>
        /// <param name="exp"></param>
        /// <returns></returns>
        public static string ReadDescription<T>(this T target, Expression<Func<T, object>> exp)
        {
            var memberExpression = exp.Body;
            if (memberExpression.NodeType == ExpressionType.Convert)
            {
                var convertExp = (UnaryExpression)memberExpression;
                memberExpression = convertExp.Operand;
            }

            if (memberExpression.NodeType == ExpressionType.MemberAccess)
            {
                var memberExp = (MemberExpression)memberExpression;
                var memberInfo = memberExp.Member;
                var attr = memberInfo.GetCustomAttributes()
                    .OfType<DescriptionAttribute>().FirstOrDefault();
                return attr.IfNotNull(i => i.Description);
            }
            if (memberExpression.NodeType == ExpressionType.Call)
            {
                var callExp = (MethodCallExpression)memberExpression;
                var methodInfo = callExp.Method;
                var attr = methodInfo.GetCustomAttributes()
                    .OfType<DescriptionAttribute>().FirstOrDefault();
                return attr.IfNotNull(i => i.Description);
            }

            Trace.Fail("不支持指定的表达式类型");
            return null;
        }

        /// <summary>
        /// 过滤一个类型的集合，筛选出指定类型的子类
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="types"></param>
        /// <returns></returns>
        public static IEnumerable<Type> FilterByParent<T>(this IEnumerable<Type> types)
        {
            return types.Where(i => typeof(T).IsAssignableFrom(i));
        }

        /// <summary>
        /// 判断指定类型是否为可空类型
        /// </summary>
        /// <param name="targeType"></param>
        /// <returns></returns>
        public static bool IsNullable(this Type targeType)
        {
            return (targeType.IsGenericType &&
                    targeType.GetGenericTypeDefinition() == typeof(Nullable<>))
                   || targeType == typeof(Nullable);
        }

        /// <summary>
        /// 当类型是可空类型时，使用其泛型参数类型作为比较
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="targetType"></param>
        /// <returns></returns>
        public static bool WhenNotNullIs<T>(this Type targetType)
        {
            if (targetType.IsNullable())
            {
                var args = targetType.GetGenericArguments();
                return args.Count() == 1 && args.First() == typeof(T);
            }
            return targetType.Is<T>();
        }

        /// <summary>
        /// 如果是一个可空类型，则返回其对应的泛型参数类型
        /// </summary>
        /// <param name="targetType"></param>
        /// <returns></returns>
        public static Type WhenNotNull(this Type targetType)
        {
            return targetType.IsNullable()
                ? targetType.GetGenericArguments().First()
                : targetType;
        }
    }
}